GraphQL Anti-Pattern - Nested Fragment
気つけなかった、GraphQLを1年以上使いました。
自分のチーム中に一番悩み課題「Nested Fragment」の解決方法をシェアします。
まずは、GraphQL Fragmentは何?
code:qoute
GraphQL fragment?
GraphQL includes reusable units called fragments. Fragments let you construct sets of fields, and then include them in queries where you need to.
GraphQL Fragmentで共通項目書いて、QueryやMutation中に組み込みできる。重複のコードを減らします。
例えば:ACardQuery も BCardQuery もTagがある
Fragment使わない書き方
code:query
const ACardQuery = gql`
query ACardQuery {
id
name
tags {
id
name
}
}
`
const BCardQuery = gql`
query BCardQuery {
id
name
tags {
id
name
}
}
`
Fragment使う書き方
code:query
const TagFragment = gql`
fragment TagFragment {
id
name
}
`
const ACardQuery = gql`
query ACardQuery {
id
name
tags {
…TagFragment
}
}
${TagFragment}
`
const BCardQuery = gql`
query BCardQuery {
id
name
tags {
…TagFragment
}
}
${TagFragment}
`
ここまで見ると、Fragmentがとても使いやすい、便利です。
でも、Fragment中にFragmentを利用する時、注意しなければいけないことがあります。
例えば、下記のQueryを定義
code:single
const AFormQuery = gql`
query AFormQuery {
id
name
bCards {
id
name
tags {
id
name
}
}
}
`
Fragment中にFragment利用する場合、
code:fragment
const TagFragment = gql`
fragment TagFragment {
id
name
}
`
const BCardFragment = gql`
fragment BCardFragment {
id
name
tags {
...TagFragment
}
}
`
const AFormFragment = gql`
fragment AFormFragment {
id
name
bCards {
...BCardFragment
}
}
`
// only reference AFormFragment, have to inject BCardFragment and TagFragment
const AFormQuery = gql`
query {
...AFormFragment
}
${AFormFragment}
${BCardFragment}
${TagFragment}
`
AFormQuery 見てください、AFormFragment だけ使ってるけど、BCardFragment TagFragment導入しないといけない。
AFormQueryようなqueryの数が増える時、codeがもっと理解にくい。
解決方法:
Fragment中にFragmentを使う時、必ずその場所で導入する、親を面倒しないでください。
code:cool
const TagFragment = gql`
fragment TagFragment {
id
name
}
`
const BCardFragment = gql`
fragment BCard {
id
name
tags {
...TagFragment
}
}
${TagFragment} // inject
`
const AFormFragment = gql`
fragment AFormFragment {
id
name
bs {
...BCardFragment
}
}
${BCardFragment} // inject
`
// only need AFormFragment
const AFormQuery = gql`
query {
...AFormFragment
}
${AFormFragment}
`